import 'package:flutter/foundation.dart';
import 'package:magicepaperapp/util/epd/driver/waveform.dart';
import 'package:magicepaperapp/util/protocol.dart';
import 'driver.dart';

class QuickLut extends Waveform {
  static const int GND = 0;
  static const int VSH = 0x40;
  static const int VSL = 0x80;
  static const int VDHR = 0x60;
  @override
  String get desc => "Quick waveform for R_sense = 4R7 and PLL = 10Hz";
  @override
  String get name => "Quick Refresh";
  @override
  int get pll => 0x01; // 10Hz
  @override
  List<Lut> get luts => [
        Lut(
            cmd: 0x20,
            data: Uint8List.fromList([
              // lut_vcom_quick
              0x01, 0x00, 10, 0x00, 0x00, 0x01, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            ])),
        Lut(
            cmd: 0x21,
            data: Uint8List.fromList([
              // lut_ww_quick
              0x01, VSL | 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            ])),
        Lut(
            cmd: 0x22,
            data: Uint8List.fromList([
              // lut_r_quick
              0x01, VSL | 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x01, 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x01, VSH | 10, 5, 0x00, 0x00, 0x02, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            ])),
        Lut(
            cmd: 0x23,
            data: Uint8List.fromList([
              // lut_w_quick
              0x01, 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x01, 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x01, 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x00, VSH | 2, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            ])),
        Lut(
            cmd: 0x24,
            data: Uint8List.fromList([
              // lut_b_quick
              0x01, 10, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x01, VSH | 12, 0x00, 0x00, 0x00, 0x01, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            ])),
      ];
}

// UC8253 commands/registers,
// define in the epaper display controller (UC8253) reference manual
class Uc8253 extends Driver {
  @override
  int get refresh => 0x12;
  @override
  int get vcomLut => 0x20;
  @override
  int get wwLut => 0x21;
  @override
  int get bwLut => 0x22;
  @override
  int get wbLut => 0x23;
  @override
  int get bbLut => 0x24;
  @override
  int get panelSetting => 0x00;
  @override
  int get pllControl => 0x30;
  @override
  WaveformList waveforms = [QuickLut()];
  @override
  get driverName => 'UC8253';
  @override
  List<int> get transmissionLines => [0x10, 0x13];

  @override
  Future<void> setlut(Protocol p, Waveform waveform) async {
    await p.writeMsg(
        Uint8List.fromList([p.fw.epdCmd, p.epd.controller.pllControl]));
    await p.writeMsg(Uint8List.fromList([p.fw.epdSend, waveform.pll])); // 10hz

    for (var lut in waveform.luts) {
      await p.writeMsg(Uint8List.fromList([p.fw.epdCmd, lut.cmd]));
      await p.writeMsg(Uint8List.fromList([p.fw.epdSend, ...lut.data]));
    }
  }

  @override
  Future<void> init(Protocol p, {Waveform? waveform}) async {
    // power on
    // FIXME: this command require polling the busy state but currently there is no way to do this in the app
    await p.writeMsg(Uint8List.fromList([p.fw.epdCmd, 0x04]));

    // VCOM_AND_DATA_INTERVAL_SETTING
    await p.writeMsg(Uint8List.fromList([p.fw.epdCmd, 0x50]));
    await p.writeMsg(Uint8List.fromList([p.fw.epdSend, 0xff, 0x0f]));

    await p.writeMsg(Uint8List.fromList([p.fw.epdCmd, panelSetting]));

    if (waveform != null) {
      await p.writeMsg(Uint8List.fromList([p.fw.epdSend, 0xEF, 0x8D]));
      await setlut(p, waveform);
    } else {
      // Otherwise, use the settings for a full refresh.
      await p.writeMsg(Uint8List.fromList([p.fw.epdSend, 0xCF, 0x8D]));
    }
  }
}
